package com.yc.zk.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

@Slf4j
@RestController
@RequestMapping(value = "/test")
@Api(tags = "Test", value = "Test API", description = "Test API")
public class TestController {

    private int sessionTimeout = 5000;
    private ZooKeeper zooKeeper = null;
    //当前client创建的子节点
    private String thisNode = null;
    //当前client等待的子节点
    private String waitNode = null;
    private String zookeeperLockRootName = "/zkLock";
    private String zookeeperLockNodeName = "/lock";
    private CountDownLatch latch = new CountDownLatch(1);
    @Value("${zookeeper.host}")
    private String zookeeperHost;

    @ApiOperation(value = "获取锁")
    @GetMapping("/getLock")
    public String getLock() throws Exception {
        return "获取锁！";
    }

    @ApiOperation(value = "释放锁")
    @GetMapping("/releaseLock")
    public String releaseLock() throws Exception {
        return "释放锁！";
    }

    @ApiOperation(value = "执行任务")
    @GetMapping("/exceTask")
    public String exceTask() throws Exception {
        exceTask1();
        return "释放锁！";
    }

    private void exceTask1() throws Exception {
        zooKeeper = new ZooKeeper(zookeeperHost, sessionTimeout, event -> {
            try {
                //连接建立时, 打开latch, 唤醒wait在该latch上的线程
                if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                    latch.countDown();
                }
                //发生了waitPath的删除事件
                if (event.getType() == Watcher.Event.EventType.NodeDeleted && event.getPath().equals(waitNode)) {
                    doSomething();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });

        //等待连接建立
        latch.await();
        //创建节点
        String nodeSequence = zooKeeper.create(zookeeperLockRootName + zookeeperLockNodeName, null
                , ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        String[] nodeSequences = nodeSequence.split("/");
        this.thisNode = nodeSequences[nodeSequences.length - 1];
        //注册监听事件
        List<String> childrenNodes = zooKeeper.getChildren(zookeeperLockRootName, false);
        //列表中只有一个子节点，那肯定就是thisNode，说明client获取锁
        if (childrenNodes.size() == 1) {
            doSomething();
        } else {
            Collections.sort(childrenNodes);
            int index = childrenNodes.indexOf(thisNode);
            if (index == -1) {
                //never happened
            } else if (index == 0) {
                //thisNode在列表中最小，当前client获取锁
                doSomething();
            } else {
                this.waitNode = zookeeperLockRootName + "/" + childrenNodes.get(index - 1);
                //在waitPath上注册监听器, 当waitPath被删除时, zookeeper会回调监听器的process方法
                zooKeeper.getData(this.waitNode, true, new Stat());
            }
        }
    }

    private void doSomething() throws Exception {
        try {
            System.out.println("获取到锁，执行任务！");
            Thread.sleep(2000);
        } finally {
            System.out.println("任务执行完毕：" + thisNode);
            zooKeeper.delete(zookeeperLockRootName + "/" + this.thisNode, -1);
            zooKeeper.close();
        }
    }
}
